package top.lemna.code.generate.util;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.visitor.VoidVisitor;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import nonapi.io.github.classgraph.json.JSONUtils;
import top.lemna.code.generate.ClassElement;
import top.lemna.code.generate.JavaField;

public class JavaParserUtils {

  public static ClassElement parserJava(String fileName) throws Exception {
    FileInputStream in = new FileInputStream(fileName);
    return parserJava(in);
  }

  public static ClassElement parserJava(InputStream inputStream) throws Exception {
    CompilationUnit compilationUnit = StaticJavaParser.parse(inputStream);
    String className = getClassName(compilationUnit);
    String classComment = getClassComment(compilationUnit);
    List<JavaField> fieldList = parserJava(compilationUnit.findAll(FieldDeclaration.class));
    List<JavaField> maxParamConsFieldList = getConstructor(compilationUnit);
    return new ClassElement(className, classComment, fieldList, maxParamConsFieldList);
  }

  private static List<JavaField> parserJava(List<FieldDeclaration> list) {
    List<JavaField> fieldList = new ArrayList<JavaField>();
    for (FieldDeclaration f : list) {
      JavaField field = parserJava(f);
      if (!field.getName().equals("serialVersionUID")) {
        fieldList.add(field);
      }
    }
    return fieldList;
  }

  /**
   * 
   * 
   * 获得参数最多的构造方法
   * 
   * @param compilationUnit
   */
  static List<JavaField> getConstructor(CompilationUnit compilationUnit) {
    List<ConstructorDeclaration> list = compilationUnit.findAll(ConstructorDeclaration.class);
    NodeList<Parameter> maxNodeList = null;
    for (ConstructorDeclaration cd : list) {
      NodeList<Parameter> nodeList = cd.getParameters();
      if (maxNodeList == null || maxNodeList.size() < nodeList.size()) {
        maxNodeList = nodeList;
      }
    }
    List<JavaField> fieldList = new ArrayList<JavaField>();
    if (maxNodeList == null)
      return fieldList;


    for (Parameter p : maxNodeList) {
      fieldList.add(new JavaField(p.getNameAsString(), p.getTypeAsString(), getComment(p), null));
    }
    return fieldList;
  }

  private static JavaField parserJava(FieldDeclaration fieldDeclaration) {
    // 注释
    String comment = getComment(fieldDeclaration);

    // 类型
    Type elementType = fieldDeclaration.getElementType();
    // 名称
    SimpleName name = fieldDeclaration.getVariables().get(0).getName();
    // 注解
    NodeList<AnnotationExpr> annotations = fieldDeclaration.getAnnotations();
    Set<String> set = new HashSet<>();
    for (AnnotationExpr annotationExpr : annotations) {
      set.add(annotationExpr.toString().replaceAll(" ", ""));
    }

    return new JavaField(name.toString(), elementType.toString(), comment, set);
  }

  private static String getComment(Parameter parameter) {

    Optional<Comment> commentOptional = parameter.getComment();
    if (!commentOptional.isPresent()) {
      return "";
    }
    Comment comment = commentOptional.get();
    String result = comment.getContent();
    return result.replaceAll("(\r\n|\r|\n|\n\r|\\*|/)", "").trim();
  }

  private static String getComment(FieldDeclaration fieldDeclaration) {

    Optional<Comment> commentOptional = fieldDeclaration.getComment();
    if (!commentOptional.isPresent()) {
      return "";
    }
    Comment comment = commentOptional.get();
    String result = comment.getContent();
    return result.replaceAll("(\r\n|\r|\n|\n\r|\\*|/)", "").trim();
  }

  private static String getClassComment(CompilationUnit compilationUnit) {
    Optional<ClassOrInterfaceDeclaration> optional =
        compilationUnit.findFirst(ClassOrInterfaceDeclaration.class);
    if (!optional.isPresent()) {
      return "";
    }
    ClassOrInterfaceDeclaration classDeclaration = optional.get();
    Optional<Comment> optionalComment = classDeclaration.getComment();
    if (!optionalComment.isPresent()) {
      return "";
    }
    Comment comment = optionalComment.get();
    String result = comment.getContent().replaceAll("(\r\n|\r|\n|\n\r|\\*|/)", "").trim();
    int endIndex = result.indexOf(" ");
    if (endIndex < 0) {
      endIndex = result.length();
    }
    return result.substring(0, endIndex);
  }

  private static String getClassName(CompilationUnit compilationUnit) {
    List<String> className = new ArrayList<>();
    VoidVisitor<List<String>> classNameVisitor = new ClassNameCollector();
    classNameVisitor.visit(compilationUnit, className);
    return className.get(0);
  }

  public static class ClassNameCollector extends VoidVisitorAdapter<List<String>> {
    @Override
    public void visit(ClassOrInterfaceDeclaration n, List<String> collector) {
      super.visit(n, collector);
      collector.add(n.getNameAsString());
    }
  }
  /*
   * public static void main(String[] args) throws Exception { List<String> className = new
   * ArrayList<>(); String FILE_PATH =
   * "C:/workspace/spring-start/spring-code-generate/src/main/java/top/lemna/freemarker/code/generate/persistence/Template.java";
   * 
   * // Create Compilation. CompilationUnit cu = StaticJavaParser.parse(new File(FILE_PATH));
   * 
   * // Create Visitor. VoidVisitor<List<String>> classNameVisitor = new ClassNameCollector(); //
   * Visit. classNameVisitor.visit(cu, className); // Print Class's name className.forEach(n ->
   * System.out.println("Class name collected: " + n)); }
   */
}
